/**
 * 
 */
package com.faxsun.core.order.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

import javax.persistence.Query;

import org.broadleafcommerce.common.locale.domain.Locale;
import org.broadleafcommerce.common.web.BroadleafRequestContext;
import org.broadleafcommerce.core.order.dao.OrderDaoImpl;
import org.broadleafcommerce.core.order.domain.Order;
import org.broadleafcommerce.profile.core.domain.Customer;
import org.hibernate.ejb.QueryHints;

import com.faxsun.core.order.domain.FSOrderImpl;
import com.faxsun.core.order.domain.FSOrderItemImpl;
import com.faxsun.core.order.service.type.FSInternalOrderStatus;
import com.faxsun.core.order.service.type.FSOrderStatus;

/**
 * 
 * 自定义OrderDao，为了实现将订单状态翻译成中文，并且增加订单状态<br/>
 * 重写所有用到{@link org.broadleafcommerce.core.order.service.type.OrderStatus}的方法
 * 
 * 
 * @author zhaoteng.song@faxsun.com
 *
 */
public class FSOrderDaoImpl extends OrderDaoImpl implements FSOrderDao {

	@Override
	public Order createNewCartForCustomer(Customer customer) {
		Order order = create();
		if (customer.getUsername() == null) {
			customer.setUsername(String.valueOf(customer.getId()));
			if (customerDao.readCustomerById(customer.getId()) != null) {
				throw new IllegalArgumentException(
						"Attempting to save a customer with an id ("
								+ customer.getId()
								+ ") "
								+ "that already exists in the database. This can occur when legacy customers have been migrated to "
								+ "Broadleaf customers, but the batchStart setting has not been declared for id generation. In "
								+ "such a case, the defaultBatchStart property of IdGenerationDaoImpl (spring id of "
								+ "blIdGenerationDao) should be set to the appropriate start value.");
			}
			customer = customerDao.save(customer);
		}
		order.setCustomer(customer);
		order.setEmailAddress(customer.getEmailAddress());
		order.setStatus(FSOrderStatus.IN_PROCESS);

		if (BroadleafRequestContext.getBroadleafRequestContext() != null) {
			order.setCurrency(BroadleafRequestContext
					.getBroadleafRequestContext().getBroadleafCurrency());
			order.setLocale(BroadleafRequestContext
					.getBroadleafRequestContext().getLocale());
		}

		if (extensionManager != null) {
			extensionManager.getProxy().attachAdditionalDataToNewCart(customer,
					order);
		}

		order = save(order);

		if (extensionManager != null) {
			extensionManager.getProxy().processPostSaveNewCart(customer, order);
		}

		return order;
	}

	@Override
	public Order submitOrder(final Order cartOrder) {
		cartOrder.setStatus(FSOrderStatus.SUBMITTED);
		Order savedOrder = save(cartOrder);
		return savedOrder;
	}

	@Override
	@SuppressWarnings("unchecked")
	public Order readNamedOrderForCustomer(final Customer customer,
			final String name) {
		final Query query = em
				.createNamedQuery("BC_READ_NAMED_ORDER_FOR_CUSTOMER");
		query.setParameter("customerId", customer.getId());
		query.setParameter("orderStatus", FSOrderStatus.NAMED.getType());
		query.setParameter("orderName", name);
		List<Order> orders = query.getResultList();

		// Filter out orders that don't match the current locale (if one is set)
		if (BroadleafRequestContext.getBroadleafRequestContext() != null) {
			ListIterator<Order> iter = orders.listIterator();
			while (iter.hasNext()) {
				Locale locale = BroadleafRequestContext
						.getBroadleafRequestContext().getLocale();
				Order order = iter.next();
				if (locale != null && !locale.equals(order.getLocale())) {
					iter.remove();
				}
			}
		}

		// Apply any additional filters that extension modules have registered
		if (orders != null && !orders.isEmpty() && extensionManager != null) {
			extensionManager.getProxy().applyAdditionalOrderLookupFilter(
					customer, name, orders);
		}

		return orders == null || orders.isEmpty() ? null : orders.get(0);
	}

	@Override
	public Order readCartForCustomer(final Customer customer) {
		Order order = null;
		final Query query = em
				.createNamedQuery("BC_READ_ORDERS_BY_CUSTOMER_ID_AND_NAME_NULL");
		query.setParameter("customerId", customer.getId());
		query.setParameter("orderStatus", FSOrderStatus.IN_PROCESS.getType());
		query.setHint(QueryHints.HINT_CACHEABLE, true);
		query.setHint(QueryHints.HINT_CACHE_REGION, "query.Order");
		@SuppressWarnings("rawtypes")
		final List temp = query.getResultList();
		if (temp != null && !temp.isEmpty()) {
			order = (Order) temp.get(0);
		}
		return order;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Order> readOrderByInternalStatus(FSInternalOrderStatus status) {
		List<Order> results = null;

		final Query query = em
				.createQuery("select orders from org.broadleafcommerce.core.order.domain.Order orders "
						+ "where orders.internalStatus=:status");

		query.setParameter("status", status.getType());
		query.setHint(QueryHints.HINT_CACHEABLE, true);
		query.setHint(QueryHints.HINT_CACHE_REGION, "query.Order");
		results = query.getResultList();
		if (results == null)
			results = new ArrayList<Order>();

		return results;
	}

	@Override
	public List<Order> readOrderByProductId(Long productId) {
		List<Order> results = new ArrayList<Order>();

		final Query query = em
				.createQuery("select orders from com.faxsun.core.order.domain.FSOrderItemImpl orders "
						+ "where orders.product.id=:productId order by orders.id desc");
		query.setParameter("productId", productId);
		query.setHint(QueryHints.HINT_CACHEABLE, true);
		query.setHint(QueryHints.HINT_CACHE_REGION, "query.FSOrderItem");
		@SuppressWarnings("unchecked")
		List<FSOrderItemImpl> queryResults = query.getResultList();

		if (results != null) {
			for (FSOrderItemImpl orderItem : queryResults) {
				if (results.size() >= 10)
					break;
				Order order = orderItem.getOrder();
				FSOrderImpl fsOrder = (FSOrderImpl) order;
				if (order.getStatus() != null
						&& order.getStatus().equals(FSOrderStatus.SUBMITTED)
						&& FSInternalOrderStatus.PAYMENT_SUCCESS.equals(fsOrder
								.getInternalStatus())) {
					
					results.add(order);
				}
			}
		}

		return results;
	}

}
